﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace TaskEditor
{

    class ZReader
    {
        private BinaryReader zBr;
        public long POS { get { return zBr.BaseStream.Position; } }

        public ZReader(string filename)
        {
            zBr = new BinaryReader(File.OpenRead(filename),Encoding.Unicode);
        }
        public int readi()
        {
            return zBr.ReadInt32();
        }
        public byte readb()
        {
            return zBr.ReadByte();
        }
        public uint readuint()
        {
            return zBr.ReadUInt32();
        }
        public string readBytesToString(int n)
        {
            var bs = zBr.ReadBytes(n);
            return string.Join(" ", bs);
        }
        public float readf()
        {
            return zBr.ReadSingle();
        }
        public string readunicode(int n)
        {
            if (n < 1)
            {
                return "";
            }
            var bs = zBr.ReadBytes(n);
            string s = Encoding.Unicode.GetString(bs);
            return s;
        }
        public string readEncoding(int n,Encoding encoding)
        {
            if (n < 1)
            {
                return "";
            }
            var bs = zBr.ReadBytes(n);
            string s = encoding.GetString(bs);
            return s;
        }
        public byte[] readbs(int n)
        {
            return zBr.ReadBytes(n);
        }

        public short reads()
        {
            return zBr.ReadInt16();
        }

        public void seek(long pos)
        {
            zBr.BaseStream.Position = pos;
        }
        public void close()
        {
            zBr.Close();
        }
        public object readObject(object readobj, string extrname = null)
        {
            Type type = readobj.GetType();
            switch (type.Name)
            {
                case "Double":
                    return zBr.ReadDouble();
                case "Char":
                    return zBr.ReadChar();
                case "UInt16":
                    return zBr.ReadUInt16();
                case "UInt32":
                    return zBr.ReadUInt32();
                case "Int32":
                    return zBr.ReadInt32();
                case "Int16":
                    return zBr.ReadInt16();
                case "Byte":
                    return zBr.ReadByte();
                case "Single":
                    return zBr.ReadSingle();
                case "Boolean":
                    return zBr.ReadBoolean();
                case "String":
                    string[] num = extrname.Split(new char[] { '_' });
                    int bnum = int.Parse(num[num.Length - 1]);
                    return Encoding.Unicode.GetString(zBr.ReadBytes(bnum));
            }
            ZSeriable se = readobj as ZSeriable;
            if (se != null)
            {
                se.beforeRead();
            }
            if (type.IsArray)
            {
                Array a = readobj as Array;
                Type basetype = a.GetType().GetElementType();
                for (int i = 0; i < a.Length; i++)
                {
                    object baseele = a.GetValue(i);
                    if (baseele==null)
                    {
                        baseele = Activator.CreateInstance(basetype);
                    }
                    a.SetValue(readObject(baseele, extrname), i);
                }
            }
            else if (type.FullName.StartsWith("System"))
            {
                throw new Exception("未处理类型.");
            }

            var mens = type.GetFields();
            foreach (var item in mens)
            {
                if (item.Name.StartsWith("_"))
                {
                    continue;
                }
                object val = item.GetValue(readobj);
                item.SetValue(readobj, readObject(val, item.Name));
            }

            if (se!=null)
            {
                se.read(this);
            }
            return readobj;
        }
        public T readt<T>() where T : class
        {
            Type type = typeof(T);
            T o = Activator.CreateInstance<T>();
            readObject(o);
            return o;
        }
    }
}
